package com.diamond.web.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.diamond.core.util.ApplicationUtils;
import com.diamond.web.dto.AssignJsTreeDto;
import com.diamond.web.dto.MenuDto;
import com.diamond.web.dto.PermissionJsTreeDto;
import com.diamond.web.dto.UrlMappingDto;
import com.diamond.web.model.system.Permission;
import com.diamond.web.service.system.PermissionService;

public class ApplicationInitUtils {
	private static ApplicationContext applicationContext;
	private static List<UrlMappingDto> urlMappingList;    
	private static List<String> allUrls;   				   //所有Controller的URL
	private static List<Permission> parentPermissionList;  //所有父权限 
	private static List<Permission> allPermissionList;	 	//所有权限
	private static List<MenuDto> allMenu;   		//所有的菜单
	private static Map<Long,List<Permission>> childrenPermission; //所有子权限 parentId:permission映射
	public final static String urlPattern="rest";
	public final static String SuperAdmin;
	public final static String SuperPwd;
	
	static{
		/**
		 * 初始化超级管理员配置
		 */
		InputStream appconfigStream = ApplicationInitUtils.class.getResourceAsStream("/application.properties");
		Properties prop = new Properties();
		try {
			prop.load(appconfigStream);
		} catch (IOException e) {
			e.printStackTrace();
		}
		SuperAdmin = prop.getProperty("SuperAdmin");
		SuperPwd = prop.getProperty("SuperPwd");
	}
	
	public static List<UrlMappingDto> getUrlMappingList() {
		return urlMappingList;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public static void appInit(ApplicationContext applicationContext){
		ApplicationInitUtils.applicationContext = applicationContext;
		initUrlList();
	}


	public static void initUrlList() {
		urlMappingList = new ArrayList<UrlMappingDto>();
		allPermissionList = new ArrayList<Permission>();
		allUrls = new ArrayList<String>();
		parentPermissionList = new ArrayList<Permission>();
		allMenu = new ArrayList<MenuDto>();
		childrenPermission = new HashMap<Long, List<Permission>>();  
		
		PermissionService permissionService = applicationContext.getBean(PermissionService.class);
		List<Permission> permissionList = permissionService.selectList();
		for (Permission p: permissionList) {
			allPermissionList.add(p);
			if(p.getParent()==null||p.getParent().getId()==0){
				parentPermissionList.add(p);
			}else{
				Long parentId = p.getParent().getId();
				if(!childrenPermission.containsKey(parentId)){
					childrenPermission.put(parentId, new ArrayList<Permission>());
				}
				childrenPermission.get(parentId).add(p);
			}
		}
		//将Map 转换为所有菜单
		for (Permission p : parentPermissionList) {
			if(p.getIsMenu()){
				MenuDto m = new MenuDto(p,urlPattern);
				if(childrenPermission.containsKey(p.getId())){
					for(Permission child:childrenPermission.get(p.getId())){
						if(child.getIsMenu()){
							m.addChlidren(new MenuDto(child,urlPattern));
						}
					}
				}
				allMenu.add(m);
			}
		}
		
		
		
		for(Class<?> clazz:getClasses("com.diamond.web.controller")){
			RequestMapping parentAnno = clazz.getAnnotation(RequestMapping.class);
			Controller controller = clazz.getAnnotation(Controller.class);
			if(controller==null){
				continue;
			}
			String parentMapping = "";
			if(parentAnno!=null){
				parentMapping = parentAnno.value().length>0?parentAnno.value()[0]:"";
			}
			findBeanMapping(clazz,parentMapping);
		}
	}

	private static void findBeanMapping(Class<?> clazz, String parentMapping) {
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			RequestMapping anno = method.getAnnotation(RequestMapping.class);
			if(anno!=null){
				String mapping = anno.value().length>0?anno.value()[0]:"";
				mapping = mapping.startsWith("/")?mapping:"/"+mapping;
				String url = parentMapping+mapping;
				UrlMappingDto urlMapping = new UrlMappingDto();
				urlMapping.setUrl(url);
				urlMapping.setClassName(clazz.getSimpleName());
				urlMapping.setParamsClass(method.getParameterTypes());
				urlMapping.setMethodName(method.getName());
				urlMapping.setRequestMethods(anno.method());
				urlMapping.setHeaders(anno.headers());
				urlMapping.setProduces(anno.produces());
				urlMapping.setParams(anno.params());
				urlMapping.setConsumes(anno.consumes());
				if(method.getAnnotation(ResponseBody.class)!=null){
					urlMapping.setReturnType("Json:"+method.getReturnType().getSimpleName());
				}else{
					urlMapping.setReturnType("View:"+method.getReturnType().getSimpleName());
				}
				urlMappingList.add(urlMapping);
				allUrls.add(urlMapping.getUrl());
			}
		}
		
	}

	public static List<String> getAllUrls() {
		return new ArrayList<String>(allUrls);
	}

	public static List<Permission> getAllParentList() {
		return new ArrayList<Permission>(parentPermissionList);
	}
	
	public static List<MenuDto> getAllMenu(){
		return new ArrayList<MenuDto>(allMenu);
	}
	
	public static List<Permission> getAllPermissions(){
		return new ArrayList<Permission>(allPermissionList);
	}
	
	public static Map<Long,List<Permission>> getChildrenPermission(){
		return new HashMap<Long,List<Permission>>(childrenPermission);
	}
	
	/**
	 * 创建权限 jsTree dto对象
	 * @param hasPermission
	 * @return
	 * @throws ReflectiveOperationException
	 */
	public static AssignJsTreeDto createPermissionTree(List<Permission> hasPermission) throws ReflectiveOperationException {
		AssignJsTreeDto dto = new AssignJsTreeDto();
		List<PermissionJsTreeDto> pDtos = new ArrayList<PermissionJsTreeDto>();
		List<Permission> parentPermission  = ApplicationInitUtils.getAllParentList();
		List<Permission> allPermission = ApplicationInitUtils.getAllPermissions();
		for (Permission parent : parentPermission) {
			PermissionJsTreeDto pdto = new PermissionJsTreeDto(parent);
			pdto.addAllChildren(allPermission);
			pDtos.add(pdto);
		}
		dto.setPermissions(pDtos);
		List<Long> hasPermissionIds = ApplicationUtils.ObjectsToFields(hasPermission,"getId",Long.class);
		dto.setHasPermisssions(hasPermissionIds);
		return dto;
	}
	
	public static Set<Class<?>> getClasses(String packageName){
		
		String packageDir = packageName.replace(".", "/");
		Set<Class<?>> classes = new HashSet<Class<?>>();
		try {
			Enumeration<URL> s = Thread.currentThread().getContextClassLoader().getResources(packageDir);
			while(s.hasMoreElements()){
				String filePath = URLDecoder.decode(s.nextElement().getFile(), "UTF-8"); 
				findAllFilePathClasses(packageName,filePath,classes);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return classes;
	}
	
	public static void findAllFilePathClasses(String packageName,
			String packagePath, Set<Class<?>> classes) {
		File dir = new File(packagePath);
		if(dir.isDirectory()){
			File [] dirFiles = dir.listFiles(new FileFilter() {
				@Override
				public boolean accept(File file) {
					return file.isDirectory()||file.getName().endsWith(".class");
				}
			});
			for (File f: dirFiles) {
				if(f.isDirectory()){
					findAllFilePathClasses(packageName+"."+f.getName(), f.getAbsolutePath(), classes);
				}else{
					String className = packageName+"."+f.getName().replace(".class", "");
					try {
						classes.add(Thread.currentThread().getContextClassLoader().loadClass(className));
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}


	
}
